BUILD := ../build
SRC := .

# Multiboot2头开始位置
MULTIBOOT2 := 0x10000
# 链接时内核入口位置，
ENTRYPOINT:=$(shell python3 -c "print(f'0x{$(MULTIBOOT2) + 64:x}')")

CFLAGS := -m32 			# 32位的程序
CFLAGS += -fno-builtin 	# 不需要gcc内置函数
CFLAGS += -nostdinc 	# 不需要标准头文件
CFLAGS += -fno-pic 		# 不需要位置无关的代码，position independent code
CFLAGS += -fno-pie 		# 不需要位置无关的可执行程序
CFLAGS += -nostdlib 	# 不需要标准库
CFLAGS += -fno-stack-protector 	# 不需要栈保护
CFLAGS := $(strip ${CFLAGS})	# 去除多余空格

DEBUG := -gdwarf				# 调试参数
INCLUDE := -I $(SRC)/include	# 头文件目录

$(BUILD)/boot/%.bin : $(SRC)/boot/%.asm
	$(shell mkdir -p $(dir $@))
	nasm -f bin -g $< -o $@

#编译内核, 采取Makefile智能检索的功能
$(BUILD)/%.o : $(SRC)/%.asm
	$(shell mkdir -p $(dir $@))
	nasm -f elf32 $(DEBUG) $< -o $@

$(BUILD)/%.o : $(SRC)/%.c
	$(shell mkdir -p $(dir $@))
	gcc $(CFLAGS) $(DEBUG) $(INCLUDE) -c $< -o $@

# 链接参数
LDFLAGS:= -m elf_i386 \
		-static \
		-Ttext $(ENTRYPOINT) \
		--section-start=.multiboot2=$(MULTIBOOT2)
LDFLAGS:=$(strip ${LDFLAGS}) 	# 去除多余空格

#链接
$(BUILD)/kernel.bin : $(BUILD)/kernel/start.o \
                      $(BUILD)/kernel/main.o \
					  $(BUILD)/kernel/io.o \
					  $(BUILD)/kernel/console.o \
					  $(BUILD)/kernel/printk.o \
					  $(BUILD)/kernel/assert.o \
					  $(BUILD)/kernel/debug.o \
					  $(BUILD)/kernel/global.o \
					  $(BUILD)/kernel/task.o \
					  $(BUILD)/kernel/thread.o \
					  $(BUILD)/kernel/mutex.o \
					  $(BUILD)/kernel/gate.o \
					  $(BUILD)/kernel/schedule.o \
					  $(BUILD)/kernel/interrupt.o \
					  $(BUILD)/kernel/handler.o \
					  $(BUILD)/kernel/clock.o \
					  $(BUILD)/kernel/time.o \
					  $(BUILD)/kernel/rtc.o \
					  $(BUILD)/kernel/memory.o \
					  $(BUILD)/kernel/keyboard.o \
					  $(BUILD)/kernel/arena.o \
					  $(BUILD)/lib/bitmap.o \
					  $(BUILD)/lib/list.o \
					  $(BUILD)/lib/fifo.o \
					  $(BUILD)/lib/string.o \
					  $(BUILD)/lib/vsprintf.o \
					  $(BUILD)/lib/stdlib.o \
					  $(BUILD)/lib/syscall.o \
					  $(BUILD)/lib/printf.o
	$(shell mkdir -p $(BUILD)/kernel/)
	ld ${LDFLAGS} $^ -o $@

$(BUILD)/system.bin : $(BUILD)/kernel.bin
	objcopy -O binary $< $@

$(BUILD)/system.map : $(BUILD)/kernel.bin
	nm $< | sort > $@

# 建立启动硬盘
$(BUILD)/master.img : $(BUILD)/boot/boot.bin \
                      $(BUILD)/boot/loader.bin \
					  $(BUILD)/system.bin \
					  $(BUILD)/system.map
# 创建一个 16M 的硬盘镜像
	yes | bximage -q -hd=16 -sectsize=512 -mode=create -imgmode=flat $@
# 将 boot.bin 写入主引导扇区
	dd if=$(BUILD)/boot/boot.bin of=$@ bs=512 count=1 conv=notrunc
# 将 loader.bin 写入硬盘
	dd if=$(BUILD)/boot/loader.bin of=$@ bs=512 count=4 seek=2 conv=notrunc
# 测试 system.bin 是否小于 100k，否则需要修改下面的 count
	test -n "$$(find $(BUILD)/system.bin -size -100k)"
# 将 system.bin 写入硬盘
	dd if=$(BUILD)/system.bin of=$@ bs=512 count=200 seek=10 conv=notrunc

# 生成ios文件，用于GNU GRUB启动
$(BUILD)/kernel.iso : $(BUILD)/kernel.bin $(SRC)/utils/grub.cfg
# 检测内核文件是否合法
	grub-file --is-x86-multiboot2 $<
# 创建 iso 目录
	mkdir -p $(BUILD)/iso/boot/grub
# 拷贝内核文件
	cp $< $(BUILD)/iso/boot
# 拷贝 grub 配置文件
	cp $(SRC)/utils/grub.cfg $(BUILD)/iso/boot/grub
# 生成 iso 文件
	grub-mkrescue -o $@ $(BUILD)/iso

# 音频驱动
SOUND := qemu-system-i386 \
    -m 32M \
	-audiodev pa,id=hda \
	-machine pcspk-audiodev=hda \
	-rtc base=localtime

# QEMU
QEMU := qemu-system-i386 \
	-m 32M \
	-rtc base=localtime

# 伪目标
.PHONY : clean bochs qemu qemug vmdk qemu-sound \
         qemug-sound qemub-sound bochsb qemub

clean :
	rm -rf $(BUILD)

# 调试前期汇编程序组成的OS
bochs : $(BUILD)/master.img
	bochs -q -f ../bochs/bochsrc -unlock

# GRUB启动
bochsb: $(BUILD)/kernel.iso
	bochs -q -f ../bochs/bochsrc.grub -unlock

# qemu参数配置：
# DISK参数
QEMU_DISK:=-boot c \
	-drive file=$(BUILD)/master.img,if=ide,index=0,media=disk,format=raw \
# CDROM参数
QEMU_CDROM:=-boot d \
	-drive file=$(BUILD)/kernel.iso,media=cdrom \
# DEBUG参数
QEMU_DEBUG:= -s -S

# 直接运行操作系统
qemu : $(BUILD)/master.img
# 新版本的qemu，在/usr/local/bin目录下
# 默认apt-get install的qeum，在/usr/bin目录下
	$(QEMU) $(QEMU_DISK)

# DEBUG 操作系统
qemug : $(BUILD)/master.img
	$(QEMU) $(QEMU_DISK) $(QEMU_DEBUG)

# CDROM GRUB引导系统
qemub: $(BUILD)/kernel.iso
	$(QEMU) $(QEMU_CDROM) \
	# $(QEMU_DEBUG)

# 直接运行操作系统(打开qemu音频驱动)
qemu-sound : $(BUILD)/master.img
	$(SOUND) $(QEMU_DISK)

# DEBUG 操作系统(打开qemu音频驱动)
qemug-sound : $(BUILD)/master.img
	$(SOUND) $(QEMU_DISK) $(QEMU_DEBUG)

# CDROM GRUB引导系统(打开qemu音频驱动)
qemub-sound : $(BUILD)/kernel.iso
	$(SOUND) $(QEMU_CDROM) \
	# $(QEMU_DEBUG)

$(BUILD)/master.vmdk : $(BUILD)/master.img
	qemu-img convert -O vmdk $< $@

# 生成可装载至VMWare的虚拟机镜像
vmdk : $(BUILD)/master.vmdk

test: $(BUILD)/master.img
